//---------------------------------------------------------------------------

#include "vcl_stl.h"
#pragma hdrstop

#include "h_base.h"
#include "h_xml.h"
#include "h_global.h"
using namespace h_base;
using namespace h_xml;

#include "h_g.h"
#include "h_stage.h"
#include "h_server.h"

#include "t_cpathform.h"
#include "t_mainform.h"
#include "h_i18n.h"
#include "h_critical.h"
#include "t_excludelistform.h"

#include "t_cpathform.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TCpathForm *CpathForm;
//---------------------------------------------------------------------------
static bool __fastcall Comp1(const HJobListInfo *lhs, const HJobListInfo *rhs)
{
   if ( lhs->ElapsedTime < rhs->ElapsedTime )
   {
      return false;
   }

   if ( lhs->ElapsedTime > rhs->ElapsedTime )
   {
      return true;
   }

   return lhs->Name < rhs->Name;
}

static bool __fastcall Comp2(const HJobListInfo *lhs, const HJobListInfo *rhs)
{
   if ( lhs->TotalElapsed < rhs->TotalElapsed )
   {
      return false;
   }

   if ( lhs->TotalElapsed > rhs->TotalElapsed )
   {
      return true;
   }

   return lhs->Name < rhs->Name;
}

static bool __fastcall Comp3(const HJobListInfo *lhs, const HJobListInfo *rhs)
{
   if ( lhs->Imbalanced < rhs->Imbalanced )
   {
      return false;
   }

   if ( lhs->Imbalanced > rhs->Imbalanced )
   {
      return true;
   }

   return lhs->Name < rhs->Name;
}

//---------------------------------------------------------------------------
__fastcall TCpathForm::TCpathForm(TComponent* Owner)
        : TForm(Owner)
{
   CommandFlag = false;
   ComboBoxType->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TCpathForm::ShowIt()
{
   if ( ComboBoxType->ItemIndex == -1 )
   {
      ComboBoxType->ItemIndex = 0;
   }

   Reload();
   ShowModal();
}

void __fastcall TCpathForm::Clear()
{
   JobMap.clear();
   JobVec.clear();
   StringGrid1->RowCount = 2;
   StringGrid1->Rows[0]->Strings[0] = UTF8String(h_g::I18nString("t_listform:NAME"));
   StringGrid1->Rows[0]->Strings[1] = UTF8String(h_g::I18nString("t_listform:PART"));
   StringGrid1->Rows[0]->Strings[2] = UTF8String(h_g::I18nString("t_listform:STATUS"));
   StringGrid1->Rows[0]->Strings[3] = UTF8String(h_g::I18nString("t_listform:START_TIME"));
   StringGrid1->Rows[0]->Strings[4] = UTF8String(h_g::I18nString("t_listform:END_TIME"));
   StringGrid1->Rows[0]->Strings[5] = UTF8String(h_g::I18nString("t_listform:ELAPSED"));

   if ( CommandFlag )
   {
      StringGrid1->Rows[0]->Strings[6] = UTF8String(h_g::I18nString("t_listform:COMMAND"));
   }
   else
   {
      StringGrid1->Rows[0]->Strings[6] = UTF8String(h_g::I18nString("t_listform:DESCRIPTION"));
   }

   StringGrid1->Rows[0]->Strings[7] = UTF8String(h_g::I18nString("t_listform:TAG"));
   StringGrid1->Rows[0]->Strings[8] = UTF8String(h_g::I18nString("t_listform:IMBALANCED"));
   StringGrid1->Rows[0]->Strings[9] = UTF8String(h_g::I18nString("t_listform:ELAPSED_TOTAL"));

   for ( int i = 0; i < 10; i++ )
   {
      StringGrid1->Rows[1]->Strings[i] = "";
   }
}

void __fastcall TCpathForm::Reload()
{
#ifdef SIMBAT_ENTERPRISE
   Reload_aux();
#endif
}

void __fastcall TCpathForm::AssignRows()
{
   set<UTF8String> ExcludeSet;

   GetExcludeList(ExcludeSet);

   JobVec.clear();

   if ( ComboBoxType->ItemIndex == 0 )
   {
      HCritical Critical(JobMap);
      Critical.Calculate(JobVec, ExcludeSet);
   }
   else if( ComboBoxType->ItemIndex == 1 )
   {
      for ( map<UTF8String, HJobListInfo>::iterator Iter = JobMap.begin();
            Iter != JobMap.end(); Iter++ )
      {
         HJobListInfo &Job = Iter->second;
         if ( ExcludeSet.find(Job.Name) == ExcludeSet.end() )
            JobVec.push_back(&Job);
      }
      sort(JobVec.begin(), JobVec.end(), Comp1);
   }
   else if( ComboBoxType->ItemIndex == 2 )
   {
      for ( map<UTF8String, HJobListInfo>::iterator Iter = JobMap.begin();
            Iter != JobMap.end(); Iter++ )
      {
         HJobListInfo &Job = Iter->second;
         if ( ExcludeSet.find(Job.Name) == ExcludeSet.end() )
            JobVec.push_back(&Job);
      }
      sort(JobVec.begin(), JobVec.end(), Comp2);
   }
   else if( ComboBoxType->ItemIndex == 3 )
   {
      for ( map<UTF8String, HJobListInfo>::iterator Iter = JobMap.begin();
            Iter != JobMap.end(); Iter++ )
      {
         HJobListInfo &Job = Iter->second;
         if ( ExcludeSet.find(Job.Name) == ExcludeSet.end() )
            JobVec.push_back(&Job);
      }
      sort(JobVec.begin(), JobVec.end(), Comp3);
   }

   vector<HJobListInfo*> NewJobVec;

   Filter(NewJobVec);

   if ( NewJobVec.empty() )
   {
      StringGrid1->RowCount = 2;
      for ( int i = 0; i < 10; i++ )
      {
         StringGrid1->Rows[1]->Strings[i] = "";
      }
      LabelTotalElapsed->Caption = "    0:00:00";
   }
   else
   {
      int Hour = 0;
      int Min = 0;
      int Sec = 0;
      UTF8String LastTime;
      int GapSec = 0;
      int GapSec2 = 0;
      StringGrid1->RowCount = NewJobVec.size() + 1;
      for ( int i = 0; i < NewJobVec.size(); i++ )
      {
         const HJobListInfo &NewInfo = *NewJobVec[i];
         AssignOneRow(i + 1, NewInfo);
         if ( NewInfo.StartTime != "" )
         {
            if ( LastTime != "" )
            {
               int TmpSec = DiffTimeSec(NewInfo.StartTime, LastTime);
               if ( TmpSec >= 120 )
               {
                  GapSec2 += TmpSec;
               }
               else
               {
                  GapSec += TmpSec;
               }
               GapSec2 += NewInfo.IdleTimeSum;
            }
            LastTime = NewInfo.EndTime;
         }
         vector<string> StrVec;
         SplitString(NewInfo.ElapsedTime.c_str(), ':', StrVec, true);
         if ( StrVec.size() != 3 )
         {
            continue;
         }
         Sec += StrToInt(StrVec[2].c_str());
         if ( Sec >= 60 )
         {
            Min += Sec / 60;
            Sec = Sec % 60;
         }
         Min += StrToInt(StrVec[1].c_str());
         if ( Min >= 60 )
         {
            Hour += Min / 60;
            Min = Min % 60;
         }
         Hour += StrToInt(StrVec[0].c_str());
      }
      UTF8String TotalElapsedStr;
      if ( ComboBoxType->ItemIndex == 0 )
      {
         TotalElapsedStr.sprintf("%5d:%02d:%02d + %3d:%02d:%02d + %3d:%02d:%02d",
            Hour, Min, Sec, GapSec / 3600, GapSec % 3600 / 60, GapSec % 60,
            GapSec2 / 3600, GapSec2 % 3600 / 60, GapSec2 % 60);
      }
      else
      {
         TotalElapsedStr.sprintf("%5d:%02d:%02d", Hour, Min, Sec);
      }
      LabelTotalElapsed->Caption = TotalElapsedStr;
   }

   JobVec = NewJobVec;
   UpdateButtons(StringGrid1->Selection.Top);
}

void __fastcall TCpathForm::AssignOneRow(int RowIdx, const HJobListInfo &Info)
{
   StringGrid1->Rows[RowIdx]->Strings[0] = Info.Name;

   vector<string> StrVec;

   SplitString(Info.Partition.c_str(), '/', StrVec, true);

   if ( StrVec.size() == 5 )
   {
      StringGrid1->Rows[RowIdx]->Strings[1] = StrVec[4].c_str();
   }
   else
   {
      StringGrid1->Rows[RowIdx]->Strings[1] = "";
   }

   StringGrid1->Rows[RowIdx]->Strings[2] = Info.Status;
   StringGrid1->Rows[RowIdx]->Strings[3] = FormatDateTime(Info.StartTime);
   StringGrid1->Rows[RowIdx]->Strings[4] = FormatDateTime(Info.EndTime);
   StringGrid1->Rows[RowIdx]->Strings[5] = Info.ElapsedTime;

   if ( CommandFlag )
   {
      StringGrid1->Rows[RowIdx]->Strings[6] = Info.Command;
   }
   else
   {
      StringGrid1->Rows[RowIdx]->Strings[6] = Info.Description;
   }

   StringGrid1->Rows[RowIdx]->Strings[7] = Info.Tag;
   StringGrid1->Rows[RowIdx]->Strings[8] = Info.Imbalanced;
   StringGrid1->Rows[RowIdx]->Strings[9] = Info.TotalElapsed;
}

void __fastcall TCpathForm::Filter(vector<HJobListInfo*> &NewJobVec)
{
   UTF8String StartTime1Filter = GetDateTime(UTF8String(EditStartTime1->Text).c_str());
   UTF8String StartTime2Filter = GetDateTime(UTF8String(EditStartTime2->Text).c_str());
   UTF8String EndTime1Filter = GetDateTime(UTF8String(EditEndTime1->Text).c_str());
   UTF8String EndTime2Filter = GetDateTime(UTF8String(EditEndTime2->Text).c_str());
   UTF8String ElapsedTimeFilter;
   int TopNFilter = EditTopN->Text.ToIntDef(0);

   if ( EditElapsedTime->Text.Trim() != "" )
   {
      int Seconds;
      vector<string> StrVec;
      char TmpStr[80 + 1];
      SplitString(UTF8String(EditElapsedTime->Text).c_str(), ':', StrVec);
      switch ( StrVec.size() )
      {
      case 0 :
         Seconds = 0;
         break;
      case 1 :
         Seconds = StrToInt(StrVec[0].c_str());
         break;
      case 2 :
         Seconds = StrToInt(StrVec[0].c_str()) * 60 +
            StrToInt(StrVec[1].c_str());
         break;
      default :
         Seconds = StrToInt(StrVec[0].c_str()) * 3600 +
            StrToInt(StrVec[1].c_str()) * 60 +
            StrToInt(StrVec[2].c_str());
         break;
      }
      snprintf(TmpStr, 80, "%02d:%02d:%02d", Seconds / 3600,
         Seconds % 3600 / 60, Seconds % 60);
      ElapsedTimeFilter = TmpStr;
   }

   int n = 0;

   NewJobVec.clear();

   for ( int i = 0; i < JobVec.size(); i++ )
   {
      if ( TopNFilter > 0 && n >= TopNFilter )
      {
         break;
      }
      HJobListInfo &Info = *JobVec[i];
      if ( StartTime1Filter != "00000000000000" && Info.StartTime < StartTime1Filter )
      {
         continue;
      }
      if ( StartTime2Filter != "00000000000000" && Info.StartTime > StartTime2Filter )
      {
         continue;
      }
      if ( EndTime1Filter != "00000000000000" && Info.EndTime < EndTime1Filter )
      {
         continue;
      }
      if ( EndTime2Filter != "00000000000000" && Info.EndTime > EndTime2Filter )
      {
         continue;
      }
      if ( ElapsedTimeFilter != "" && Info.ElapsedTime < ElapsedTimeFilter )
      {
         continue;
      }
      NewJobVec.push_back(&Info);
      n++;
   }
}

void __fastcall TCpathForm::ButtonCalculateClick(TObject *Sender)
{
   Reload();
}
//---------------------------------------------------------------------------

void __fastcall TCpathForm::UpdateButtons(int Row)
{
   UTF8String JobName = StringGrid1->Rows[Row]->Strings[0];
   HStage *Stage = MainForm->FindControlByName(JobName);

   if ( Stage == NULL )
   {
      ButtonProperty->Enabled = false;
      ButtonGotoThisGroup->Enabled = false;
      return;
   }

   ButtonProperty->Enabled = true;
   ButtonGotoThisGroup->Enabled = true;
}

void __fastcall TCpathForm::StringGrid1SelectCell(TObject *Sender, int ACol,
      int ARow, bool &CanSelect)
{
   UpdateButtons(ARow);
}
//---------------------------------------------------------------------------

void __fastcall TCpathForm::ButtonPropertyClick(TObject *Sender)
{
   UTF8String JobName = StringGrid1->Rows[StringGrid1->Selection.Top]->Strings[0];
   HStage *Stage = MainForm->FindControlByName(JobName);

   if ( Stage == NULL )
   {
      return;
   }

   Stage->EditProperty();
}
//---------------------------------------------------------------------------

void __fastcall TCpathForm::ButtonGotoThisGroupClick(TObject *Sender)
{
   UTF8String JobName = StringGrid1->Rows[StringGrid1->Selection.Top]->Strings[0];

   if ( JobName == "" )
   {
      return;
   }

   MainForm->GotoGroupAndFocusToJob(JobName);
   Close();
}
//---------------------------------------------------------------------------

void __fastcall TCpathForm::ButtonDescriptionClick(TObject *Sender)
{
   CommandFlag = !CommandFlag;

   if ( CommandFlag )
   {
      StringGrid1->Rows[0]->Strings[6] = UTF8String(h_g::I18nString("t_listform:COMMAND"));
   }
   else
   {
      StringGrid1->Rows[0]->Strings[6] = UTF8String(h_g::I18nString("t_listform:DESCRIPTION"));
   }

   for ( int i = 0; i < JobVec.size(); i++ )
   {
      const HJobListInfo &Info = *JobVec[i];
      if ( CommandFlag )
      {
         StringGrid1->Rows[i + 1]->Strings[6] = Info.Command;
      }
      else
      {
         StringGrid1->Rows[i + 1]->Strings[6] = Info.Description;
      }
   }
}
//---------------------------------------------------------------------------

void __fastcall TCpathForm::ButtonSaveClick(TObject *Sender)
{
   SaveDialog1->DefaultExt = "csv";
   SaveDialog1->Filter =
      "Comma-Separated Values (*.csv)|*.csv|All files (*.*)|*.*";
   SaveDialog1->FilterIndex = 1;

   if ( SaveDialog1->InitialDir == "" )
   {
      SaveDialog1->InitialDir = h_g::BaseDir + "bats";
   }

   SaveDialog1->Options = TOpenOptions() << ofOverwritePrompt
      << ofEnableSizing;
   SaveDialog1->Title = UTF8String(h_g::I18nString("t_downloadform:SAVE_FILE_AS"));

   if( !SaveDialog1->Execute() )
   {
      return;
   }

   FILE *f = _wfopen(SaveDialog1->FileName.c_str(), L"wt");

   if ( f == NULL )
   {
      UTF8String TmpStr;
      h_g::ShowMessage(TmpStr.sprintf("Can not create %s", SaveDialog1->FileName.c_str()));
   }

   for ( int i = 0; i < StringGrid1->RowCount; i++ )
   {
      vector<UTF8String> StrVec;

      for ( int j = 0; j < 10; j++ )
      {
         StrVec.push_back(StringGrid1->Rows[i]->Strings[j]);
      }

      fprintf(f, "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
         StrVec[0].c_str(), StrVec[1].c_str(), StrVec[2].c_str(),
         StrVec[3].c_str(), StrVec[4].c_str(), StrVec[5].c_str(),
         StrVec[7].c_str(), StrVec[8].c_str(), StrVec[9].c_str(),
         StrVec[6].c_str());
   }

   fclose(f);
}
//---------------------------------------------------------------------------

void __fastcall TCpathForm::ButtonEditExcludeListClick(TObject *Sender)
{
   int Top = StringGrid1->Selection.Top;
   int Bottom = StringGrid1->Selection.Bottom;
   UTF8String Key;

   if ( Top > Bottom )
   {
      Key = "";
   }
   else
   {
      Key = StringGrid1->Rows[Top]->Strings[0];
   }

   set<UTF8String> StrSet;

   h_g::GetExcludeList(StrSet);
   CheckBoxExcludeList->Checked = true;

   if ( !ExcludeListForm->EditExcludeList(StrSet, Key) )
   {
      return;
   }

   h_g::SetExcludeList(StrSet);
}
//---------------------------------------------------------------------------
void __fastcall TCpathForm::GetExcludeList(set<UTF8String> &StrSet)
{
   if ( CheckBoxExcludeList->Checked )
   {
      h_g::GetExcludeList(StrSet);
   }
   else
   {
      StrSet.clear();
   }
}

